﻿using System;
using System.Web;
using System.Web.Mvc;
using DNT.RavenQA.Core.Extensions;
using Elmah;

namespace DNT.RavenQA.Web.Infrastructure.Logging
{
    /// <remarks>
    /// http://stackoverflow.com/questions/766610/how-to-get-elmah-to-work-with-asp-net-mvc-handleerror-attribute
    /// </remarks>
    public class HandleErrorWithElmahAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext context)
        {
            base.OnException(context);

            var e = context.Exception;

            if (!context.ExceptionHandled ||    // if unhandled, will be logged anyhow
                RaiseErrorSignal(e) ||          // prefer signaling, if possible
                IsFiltered(context))            // filtered?
                return;

            LogException(e);
        }

        private static Boolean RaiseErrorSignal(Exception e)
        {
            var context = HttpContext.Current;

            if (context.IsNull())
                return false;

            var signal = ErrorSignal.FromContext(context);

            if (signal.IsNull())
                return false;

            signal.Raise(e, context);

            return true;
        }

        private static Boolean IsFiltered(ExceptionContext context)
        {
            var config = context.HttpContext.GetSection("elmah/errorFilter") as ErrorFilterConfiguration;

            if (config.IsNull())
                return false;

            var testContext = new ErrorFilterModule.AssertionHelperContext(context.Exception, HttpContext.Current);
            return config.Assertion.Test(testContext);
        }

        private static void LogException(Exception e)
        {
            var context = HttpContext.Current;
            ErrorLog.GetDefault(context).Log(new Error(e, context));
        }
    }
}